package pac

import (
	"encoding/hex"
	"fmt"
	"regexp"
	"slgw_web/serial/dto"
	"slgw_web/serial/util"
	"strconv"
	"strings"
	"time"

	"github.com/jacobsa/go-serial/serial"
)

//var stopTimerCh = make(chan struct{})

func init() {
	GetSerialInit()
	GetSerial_SlavelInit()
	Serial_Slave_DetailInit()
	SerialClient()
	GetDLT645data()
}
func PortRestart(id int64) {
	if !util.StopRestart { //是否禁止重连
		for i, _ := range Test {
			if Test[i].DataID == id {
				Test[i].Port.Close()
				//重连
				port, err := serial.Open(Test[i].Options)
				if err != nil {
					util.Error("PortName:" + Test[i].ComName + ",DLT645串口开启失败:" + err.Error())
					return
				}
				//成功
				newData := dto.CollectSet{
					Port:       port,
					DataID:     id,
					ComName:    Test[i].ComName,
					Options:    Test[i].Options,
					IsEnd:      true,
					DLTisSend:  true,
					SerialID:   Test[i].SerialID,
					TPITV:      Test[i].TPITV,
					Timeout:    Test[i].Timeout,
					RetryCount: Test[i].RetryCount,
				}
				util.Error("PortName:" + Test[i].ComName + ",DLT645串口重启成功")
				// 找到匹配的数据，将其替换为新的数据
				Test[i] = newData
				break // 找到后退出循环
			}
		}
	}
}

// 串口初始化
func SerialClient() {
	//Test = Test[:0]
	for _, data := range util.Serial {
		if data.Agreement == "2" { //DLT645模式
			baudRate, err := strconv.Atoi(data.BAD)
			if err != nil {
				util.Error(data.ComName + "的波特率转换失败")
			}
			dataBits, err := strconv.Atoi(data.DAB)
			if err != nil {
				util.Error(data.ComName + "的数据位转换失败")
			}
			stopBits, err := strconv.Atoi(data.STO)
			if err != nil {
				util.Error(data.ComName + "的停止位转换失败")
			}
			var parityMode serial.ParityMode
			if data.CHC == "N" {
				parityMode = 0

			} else if data.CHC == "O" {
				parityMode = 1
			} else {
				parityMode = 2
			}
			options := serial.OpenOptions{
				BaudRate:              uint(baudRate),
				DataBits:              uint(dataBits),
				StopBits:              uint(stopBits),
				InterCharacterTimeout: 100,
				PortName:              data.ComName,
				ParityMode:            parityMode,
				//MinimumReadSize: 0,
			} //初始化结构体变量
			port, err := serial.Open(options)
			if err != nil {
				util.Error("PortName:" + data.ComName + ",DLT645串口开启失败:" + err.Error())
				return
			}
			if data.TPITV == "" || data.TPITV == "0" {
				data.TPITV = "60"

			}
			tpitv, err := strconv.Atoi(data.TPITV)
			if err != nil {
				util.Error(data.ComName + "的采集周期时间配置错误,将默认为60秒")
				tpitv = 60
			}
			dlt645 := dto.CollectSet{
				Port:       port,
				DataID:     data.ID,
				ComName:    data.ComName,
				Options:    options,
				IsEnd:      true,
				DLTisSend:  true,
				SerialID:   data.ID,
				TPITV:      tpitv,
				Timeout:    int(data.Timeout),
				RetryCount: data.RetryCount,
			}
			// lock := dto.DLT645Lock{
			// 	DLTisSend: true,
			// 	SerialID:  data.ID,
			// }
			Test = append(Test, dlt645)
			// util.DLT645Lock = append(util.DLT645Lock, lock)
			// fmt.Println("util.DLT645Data", util.DLT645Data)
			// fmt.Println("util.DLT645Lock", util.DLT645Lock)
		}
	}
}

// 获取返回的参数
func GetDLT645data() {
	for i := range Test {
		i2 := i
		//获取返回的参数
		if Test[i2].Port != nil {
			go func() {
				receivedData := false
				buffer := make([]byte, 0)

				for {
					buf := make([]byte, 64)
					n, err := Test[i2].Port.Read(buf)
					if err != nil {
						fmt.Println("串口：" + Test[i2].ComName + ",dlt645获取参数错误:" + err.Error())
						time.Sleep(10 * time.Second)
					} else {
						if n == 0 {
							if receivedData {
								//fmt.Printf("%x", buffer)      // 输出已拼接的 buffer
								dataStr := BytesToHex(buffer) //获取字符串参数
								//fmt.Println("dlt645返回参数:", dataStr)
								dataS := analysisData(dataStr)
								dataList := strings.Split(dataS, ",")
								if len(dataList) < 4 {
									buffer = make([]byte, 0) // 重置 buffer
									receivedData = false
									Test[i2].DLTisSend = true
									//stopTimerCh <- struct{}{}
									//util.Error("ComName:" + Test[i2].ComName + ",读取参数有误,dataS:" + dataStr)
								} else {

									datas := dataList[0]
									code := dataList[1] //返回的code
									datareal := dataList[2]
									addressID := dataList[3]
									var serial_Slave_ID int64 = 0
									//获取serial_slave_id
									for _, serial_Slave := range util.Serial_Slave {
										if serial_Slave.IsCollect == 1 {
											//获取反转的地址位
											modbusSlaveID := ChangeStr(serial_Slave.ModbusSlaveID)
											if modbusSlaveID == addressID {
												serial_Slave_ID = serial_Slave.ID
												// for i := range util.DLT645Lock {
												if Test[i2].SerialID == serial_Slave.Serial_ID {
													//改变串口锁
													Test[i2].DLTisSend = true
												}
												// }
											}
										}
									}
									AddDataDLT645(Test[i2].DataID, serial_Slave_ID, code, datas, datareal, datas)
									// SendDataByte(buffer)
									buffer = make([]byte, 0) // 重置 buffer
									receivedData = false

								}
							}
						} else {
							buf = buf[:n]
							ss := buf[n-1]
							s := fmt.Sprintf("%02X", ss)
							if s == "16" { //结尾
								if len(buffer) > 50 {
									util.Error("dlt645协议采集错误,ComName:" + Test[i2].ComName + ",返回参数解析失败,data:" + BytesToHex(buffer))
									buffer = make([]byte, 0) // 重置 buffer
									receivedData = false
								} else {
									receivedData = true
								}
							}
							buffer = append(buffer, buf...)
						}
					}
				}

			}()
		}
	}
}
func SendDLT645Data(t dto.CollectSet) {
	go func() {
		j := 0
		for i := range Test {
			if t.DataID == Test[i].DataID {

				t = Test[i]
				j = i
				Test[i].IsEnd = false
				break
			}
		}
		if t.IsEnd {
			//fmt.Println("dlt645t", t)
			//if t.Port != nil {
			//fmt.Println("进入", t.DataID, t.IsEnd)
			for _, data2 := range util.Serial_Slave {
				if data2.IsCollect == 1 {
					if data2.Serial_ID == t.DataID { //拿到同一个串口下的所有电表
						//fmt.Println("电表", data2)
						//获取该串口的广播位
						slaveID := ChangeStr(data2.ModbusSlaveID) //获取反转的地址位

						for _, item := range util.Serial_Slave_Detail {
							count := 0
							if item.Serial_ID == t.DataID && item.Serial_Slave_ID == data2.ID && item.Type == 0 && item.Code != nil && *item.Code != "" {
								codeStr := changeCode(*item.Code)
								//fmt.Println("codeStr", codeStr)
								if codeStr != "" {

									// 初始化条件变量
									//fmt.Println("util.DLT645Lock[i]", util.DLT645Lock[i])

									for {
										//fmt.Println("count", count)
										time.Sleep(100 * time.Millisecond)

										if Test[j].DLTisSend {
											//fmt.Println("util.DLT645Lock[i]", Test[j].DLTisSend)
											break
										}
										if count == 10 {
											Test[j].DLTisSend = true
											break
										}
										count++
										//fmt.Println("util.DLT645Lock[i]", Test[j].DLTisSend)
										//fmt.Println("count", count)
									}
									count = 0
									//锁住，等待返回成功或者定时结束 解锁
									Test[j].DLTisSend = false
									hexStr := CalculateChecksum("68" + slaveID + "681104" + codeStr)
									requestHex := "68" + slaveID + "681104" + codeStr + hexStr + "16"
									requestBytes, err := hex.DecodeString(requestHex)
									if err != nil {
										Test[j].DLTisSend = true
										//stopTimerCh <- struct{}{}
										util.Error("dlt645发送错误：" + err.Error())

									}
									//发送数据
									// fmt.Println("dlt645发送参数：" + requestHex)
									// fmt.Println("data:", util.DLT645Data[i].Port)
									_, err = Test[j].Port.Write(requestBytes)
									if err != nil {
										Test[j].DLTisSend = true
										//stopTimerCh <- struct{}{}
										util.Error("串口：" + t.ComName + ",dlt645发送错误:" + err.Error() + "，重新连接中")
										PortRestart(t.DataID)
									}

								} else {
									Test[j].DLTisSend = true
									//stopTimerCh <- struct{}{}
									util.Error(t.ComName + data2.Name + item.Name + "发送dlt645错误，code参数不正确")
								}
							}
						}
						time.Sleep(2 * time.Second)
					} else {
						logStr := "Name:" + data2.Name + ",已配置不进行采集"
						util.IsCollectLog(logStr)
					}
				}

			}
			for i := range Test {
				if t.DataID == Test[i].DataID {
					Test[i].IsEnd = true
					break
				}
			}
		} else {
			//fmt.Println("当前采集未结束", t.DataID, t.IsEnd)
			return
		}

	}()
}

// 将获取的数据插入对应的位置
func AddDataDLT645(serial_ID int64, serial_Slave_ID int64, code string, collectData string, datareal string, value3 string) {
	// fmt.Println("adddata", serial_ID, serial_Slave_ID, types, collectData)
	for i := 0; i < len(util.Serial_Slave_Detail); i++ {
		data := util.Serial_Slave_Detail[i]
		if data.Code != nil {
			codeStr := changeCode(*data.Code)
			if codeStr != "" {
				if data.Serial_ID == serial_ID && data.Serial_Slave_ID == serial_Slave_ID && codeStr == code {
					cdata := collectData //需要采集位置的数据
					test1 := dto.Serial_Slave_Detail_Cache{
						ID:               data.ID,
						Serial_ID:        data.Serial_ID,
						Serial_Slave_ID:  data.Serial_Slave_ID,
						CollectAddressID: *data.CollectAddressID,
						Type:             data.Type,
						Value:            cdata,
						CreateTime:       time.Now().Format("2006-01-02 15:04:05"),
						Value2:           &datareal,
						Value3:           &value3,
					}
					// 在 append 之前，遍历 collectDataListNew，根据 ID 判断是否需要覆盖
					updated := false
					for i, data := range util.CollectDataList {
						if data.ID == test1.ID {
							// 找到相同 ID 的元素，进行覆盖
							util.CollectDataList[i] = test1
							updated = true
							break
						}
					}
					// 如果没有找到相同 ID 的元素，进行追加
					if !updated {
						util.CollectDataList = append(util.CollectDataList, test1)
					}
				}
			}
		}
	}
}

// 将 []byte 切片转换为16进制字符串并拼接
func BytesToHex(input []byte) string {
	hexString := ""
	for _, b := range input {
		// 使用 %02X 格式化字符串将字节转换为两位16进制表示，并拼接到 hexString 中
		hexString += fmt.Sprintf("%02X", b)
	}
	return hexString
}

// 解析参数
func analysisData(data string) string {

	if contains6891(data) {
		// 获取"6891"之后的内容
		after6891 := getContentAfter6891(data)
		return after6891
	} else {
		//fmt.Println("不包含'6891'")
		return ""
	}
}

// 判断字符串是否包含"6891"
func contains6891(input string) bool {
	match, _ := regexp.MatchString("6891", input)
	return match
}

// 获取"6891"之后的内容
func getContentAfter6891(input string) string {
	re := regexp.MustCompile("6891(.+)")
	match := re.FindStringSubmatch(input)
	re0 := regexp.MustCompile("68(.+)")
	ss := re0.FindStringSubmatch(input)
	if len(ss[1]) < 12 {
		return ""
	}
	addressID := ss[1][0:12]
	if len(match) > 1 {
		data := match[1]
		//fmt.Println("包含'6891'，'6891'之后的内容是：", data)
		if len(data) < 10 {
			return ""
		}
		datas := GetData(data)
		if datas == "" {
			return ""
		}
		return datas + "," + addressID
	}
	return ""
}

// 06 33 34 34 35     54 55    F4 16
func GetData(input string) string {
	length := input[0:2]
	// num, _ := strconv.Atoi(length)
	num, _ := strconv.ParseInt(length, 16, 64)
	diNumStart := 2          //di开始位
	diNumEnd := 10           //di结束位
	dataNumStart := diNumEnd //数据开始位
	dataNumEnd := num*2 + 2  //数据结束位
	if int64(len(input)) < dataNumEnd {
		return ""
	}
	didata := input[diNumStart:diNumEnd]   //code请求参数
	data := input[dataNumStart:dataNumEnd] //原始返回数据
	datas := GetDataString(data)           //加了00的数据
	datareal := GetRealData(data)          //获取转换后的真实数据
	// fmt.Println("didata", didata)
	// fmt.Println("data", data)
	// fmt.Println("datas", datas)
	// fmt.Println("datareal", datareal)
	return datas + "," + didata + "," + datareal
}

// 将参数按两位隔开并拼上00
func GetDataString(a string) string {

	c := ""
	for i := 0; i < len(a); i += 2 {
		b := "00" + a[i:i+2]
		c += b
	}
	return c
}

// 字符串换位置
func ChangeStr(input string) string {
	// 将字符串转换为 rune 切片
	runes := []rune(input)

	// 反转 rune 切片
	reversed := reverseRuneSlice(runes)

	// 将反转后的 rune 切片转换回字符串
	input = string(reversed)
	// 获取字符串长度
	length := len(input)

	// 创建一个切片来存储每两个字符的组合
	var pairs []string

	// 遍历字符串并每两个字符交换位置
	for i := 0; i < length; i += 2 {
		// 确保有足够的字符可供交换
		if i+1 < length {
			pair := string(input[i+1]) + string(input[i])
			pairs = append(pairs, pair)
		} else {
			// 如果字符串长度为奇数，最后一个字符保持不变
			pairs = append(pairs, string(input[i]))
		}
	}

	// 将切片中的元素连接成一个字符串
	result := ""
	for _, pair := range pairs {
		result += pair
	}
	return result
}

// 获取真实数据
func GetRealData(input string) string {
	// 将字符串转换为 rune 切片
	runes := []rune(input)

	// 反转 rune 切片
	reversed := reverseRuneSlice(runes)

	// 将反转后的 rune 切片转换回字符串
	input = string(reversed)
	// 获取字符串长度
	length := len(input)

	// 创建一个切片来存储每两个字符的组合
	var pairs []string

	// 遍历字符串并每两个字符交换位置
	for i := 0; i < length; i += 2 {
		// 确保有足够的字符可供交换
		if i+1 < length {
			pair := string(input[i+1]) + string(input[i])
			data, _ := strconv.ParseInt(pair, 16, 64)
			data33, _ := strconv.ParseInt("33", 16, 64)
			str1 := fmt.Sprintf("%02X", data-data33) // 转成16进制
			pairs = append(pairs, str1)
		} else {
			// 如果字符串长度为奇数，最后一个字符保持不变
			pairs = append(pairs, string(input[i]))
		}
	}

	// 将切片中的元素连接成一个字符串
	result := ""
	for _, pair := range pairs {
		result += pair
	}
	return result
}

// 反转字符串
func reverseRuneSlice(slice []rune) []rune {
	length := len(slice)
	reversed := make([]rune, length)
	for i, r := range slice {
		reversed[length-i-1] = r
	}
	return reversed
}

// 将code转成dlt645所需的参数
func changeCode(code string) string {
	di := strings.Split(code, ",")
	codeStr := ""
	if len(di) > 3 {

		di1, _ := strconv.ParseInt(di[0], 16, 64) //转成int类型
		di2, _ := strconv.ParseInt(di[1], 16, 64)
		di3, _ := strconv.ParseInt(di[2], 16, 64)
		di4, _ := strconv.ParseInt(di[3], 16, 64)
		data, _ := strconv.ParseInt("33", 16, 64)
		str1 := fmt.Sprintf("%X", di1+data) //+33 转成16进制
		str2 := fmt.Sprintf("%X", di2+data)
		str3 := fmt.Sprintf("%X", di3+data)
		str4 := fmt.Sprintf("%X", di4+data)
		if len(str1) > 2 {
			str1 = str1[len(str1)-2:]
		}
		if len(str2) > 2 {
			str2 = str2[len(str2)-2:]
		}
		if len(str3) > 2 {
			str3 = str3[len(str3)-2:]
		}
		if len(str4) > 2 {
			str4 = str4[len(str4)-2:]
		}

		codeStr = str4 + str3 + str2 + str1
	}
	return codeStr
}
